﻿// An example script that demonstrates the effect of connection weights and delays
// Generates a figure showing the effect of connection weights and delays
// see Shared Figures/Connection weights and lengths.svg

// The script creates a three neuron CrossbarNetwork network with an attached data collector (OneMillisecTickDataCollector)
// Running the network accumulates membrane voltage data in the data collector that can then be displayed

// Note that DLL reference order is very important
#r @"C:\Users\Mira\Source\Repos\Spinula\Debug\SpikingNeuronLib.dll"
#r @"C:\Users\Mira\Source\Repos\Spinula\SpikingAnalyticsBaseLib\bin\Debug\SpikingAnalyticsBaseLib.dll"
#r @"C:\Users\Mira\Source\Repos\Spinula\SpikingAnalyticsLib\bin\Debug\SpikingAnalyticsLib.dll"
#I @"C:\Users\Mira\Source\Repos\Spinula\packages\RProvider.1.0.12"
#load "RProvider.fsx"
#I @"C:\Users\Mira\Source\Repos\Spinula\packages\Deedle.1.0.0"
#load "Deedle.fsx"
#r @"C:\Users\Mira\Source\Repos\Spinula\SpikingVisualisationRLib\bin\Debug\SpikingVisualisationRLib.dll"    // references Deedle
#r @"C:\Users\Mira\Source\Repos\Spinula\SpikingAnalyticsFrameLib\bin\Debug\SpikingAnalyticsFrameLib.dll"    // references Deedle

open System
open SpikingNeuronLib
open SpikingAnalyticsLib
open SpikingVisualisationRLib

// Generate membrane voltage data for a network with a single output neuron
let GenerateMembraneData numberOfInputs delays (weights:float list) stimulus =

    let network =
        let numberOfSamples = 5000
        let specifier =
            let postNeuron = numberOfInputs
            let connections =
                Seq.zip3 [ for i in 0..numberOfInputs-1 -> i ] delays weights // -> (preNeuron, delay, weight)
                |> Seq.map (fun (preNeuron, delay, weight) -> new Connection(preNeuron, postNeuron, delay, weight))
                |> Seq.toList
            new CrossbarNetworkSpecifier(numberOfInputs + 1, 0, 20, connections)
        let hiResCollector =
            let selectedNeurons = [ specifier.TotalNeurons-1 ]   // just the output neuron
            let selectedConnections = []
            let totalNeurons = specifier.TotalNeurons
            let totalConnections = specifier.Connections.Value.Count
            let numberOfMembraneSamples = numberOfSamples
            let numberOfWeightSamples = 0
            let parameters = new OneMillisecTickDataCollectorParameters(selectedNeurons, totalNeurons, selectedConnections, totalConnections, numberOfMembraneSamples, numberOfWeightSamples)
            new OneMillisecTickDataCollector(parameters)
        CrossbarNetwork.CreateAdHocNetwork(specifier, Some(hiResCollector), false)

    network.Run(10, Some(stimulus :> IStimulus), 0, false)
    network.OneMillisecondEventCollector.Value

// Generate and show membrane data
let GenerateMembraneDataHelper numberOfInputs delays weights =

    let stimulus =
        let firingEvents =
            let times = [ for i in 0..numberOfInputs-1 -> 0 ]
            let neurons = [ for i in 0..numberOfInputs-1 -> i ]
            Seq.zip times neurons
            |> Seq.map (fun (time, nindex) -> new FiringEvent(time, nindex, EventLabel.Foreground))
            |> Seq.toArray
        let patternStimulationsPerSecond = 1
        Stimulus.Create(patternStimulationsPerSecond, firingEvents)

    let dataCollector = GenerateMembraneData numberOfInputs delays weights stimulus

    printfn "%s" (String.Join(" ", dataCollector.GetSpikeTimes(0)))
    MillisecondResolutionDataVisualisation.ShowCollectedMembraneData(dataCollector, 1000, 1100)

GenerateMembraneDataHelper 2 [ 5; 5; ] [ 10.0; 10.0; ]
GenerateMembraneDataHelper 2 [ 5; 5; ] [ 9.0; 8.0; ]
GenerateMembraneDataHelper 2 [ 5; 5; ] [ 8.0; 8.0; ]

GenerateMembraneDataHelper 2 [ 6; 5; ] [ 10.0; 10.0; ]
GenerateMembraneDataHelper 2 [ 8; 5; ] [ 10.0; 10.0; ]
GenerateMembraneDataHelper 2 [ 12; 5; ] [ 10.0; 10.0; ]
